home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
ASSEMBLE
/
H279.ZIP
/
WASM223.ZIP
/
SLEEPERM.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-10-05
|
27KB
|
957 lines
; SLEEPER, Monochrome Version
; by Eric Tauck
;
; This program is a TSR that automatically disables
; a monochrome adapter after a specified amount of
; time to prevent screen burn-in.
;
; IMPORTANT NOTE: I figured out how to enable and
; disable a monochrome adapter by hacking another
; program. Since I don't have any formal
; documentation on how to perform monochrome
; blanking, I don't guarantee that this program
; will work with all monchrome adapters. Beware
; that the monitor can be physically damaged by
; messing around with the adapter ports.
UNUSED+
JUMP+
jmp start ;jump to entry point
;****************************************
; Resident Data
VER_HI EQU 1 ;high version number
VER_LO EQU 30 ;low version number
SIGN1 EQU 0534CH ;first part of signature
SIGN2 EQU 04550H ;second part of signature
BIOSEG EQU 0040H ;BIOS data area segment
BIOSHF EQU 0017H ;BIOS shift bits
SMASK EQU 00001111B ;hot key shift mask
SHIFT EQU 00001100B ;hot key shift bits (CONTROL + ALTERNATE)
func DB ? ;keyboard function number
;--- original interrupt handlers
int_09 LABEL DWORD ;old interrupt 9
DW ?
DW ?
int_16 LABEL DWORD ;old interrupt 16
DW ?
DW ?
int_1C LABEL DWORD ;old interrupt 1C
DW ?
DW ?
int_21 LABEL DWORD ;old interrupt 21
DW ?
DW ?
;--- flags
FIXED EQU 0001H ;video state fixed
DISPL EQU 0002H ;video displayed
FORCE EQU 0004H ;forced timeout
flags DW 0000H ;current flag settings
;--- timer data
ticks DW 5460 ;count value (5 min * 60 sec/min * 18.2 tic/sec)
timer DW ? ;timer value
;--- resident functions
NOTHING EQU 0 ;do nothing
RESET EQU 1 ;reset timer
SHOW EQU 2 ;screen on
HIDE EQU 3 ;screen off
TIME EQU 4 ;force timeout
functab LABEL WORD ;resident function table
DW OFFSET dummy
DW OFFSET screen_reset
DW OFFSET screen_on
DW OFFSET screen_off
DW OFFSET timeout
;****************************************
; Resident Code
;========================================
; Low level control.
;--- reset timer
reset_timer PROC NEAR
seg cs
push ticks ;ticks on stack
seg cs
pop timer ;load timer
ret
ENDP
;--- turn off video
video_off PROC NEAR
push ax
push dx
mov dx, 3B8H
mov al, 21H
out dx, al
seg cs
and flags, NOT DISPL ;clear flag
pop dx
pop ax
ret
ENDP
;--- turn on video
video_on PROC NEAR
push ax
push dx
mov dx, 3B8H
mov al, 29H
out dx, al
seg cs
or flags, DISPL ;set flag
pop dx
pop ax
ret
ENDP
;========================================
; Screen functions.
;--- reset screen timer
screen_reset PROC NEAR
seg cs
and flags, NOT FIXED ;clear fixed flag
call reset_timer ;reset timer
seg cs
test flags, DISPL ;check if screen on
jnz novon
call video_on ;turn on screen
novon ret
ENDP
;--- force timeout
timeout PROC NEAR
seg cs
and flags, NOT FIXED ;clear fixed flag (reset)
seg cs
or flags, FORCE ;set forced timeout flag
seg cs
mov timer, 18 ;set timer to two seconds
ret
ENDP
;--- turn screen off
screen_off PROC NEAR
seg cs
or flags, FIXED ;set fixed flag
seg cs
mov timer, 0 ;zero timer
call video_off ;turn off screen
ret
ENDP
;--- screen on
screen_on PROC NEAR
seg cs
or flags, FIXED ;set fixed flag
seg cs
mov timer, 0 ;zero timer
call video_on ;turn on screen
ret
ENDP
;--- dummy function
dummy PROC NEAR
ret
ENDP
;--- transfer to screen routine in BX
screen_func PROC NEAR
shl bx ;convert number to offset
seg cs
jmp WORD [functab + bx] ;branch to routine
ENDP
;========================================
; Interrupt 09H handler.
key_han PROC NEAR
seg cs
test flags, FIXED OR FORCE ;check if fixed state or forced timeout
jnz kdone
call screen_reset ;reset timer and screen
kdone seg cs
jmp int_09 ;branch to old keyboard handler
ENDP
;========================================
; Check for a hotkey and pass command
; to resident sleeper. NOTE: all the
; flags except CY are preserved.
;
; In: AH= scan code.
;
; Out: CY= set if hotkey pressed,
; cleared if not.
key_check PROC NEAR
pushf
push ax
push bx
;--- check scan code
mov bx, RESET
cmp ah, 19 ;R - reset timer
je kshft
mov bx, SHOW
cmp ah, 47 ;V - visible screen
je kshft
mov bx, HIDE
cmp ah, 35 ;H - hidden screen
je kshft
mov bx, TIME
cmp ah, 20 ;T - force timeout
je kshft
kcdone pop bx
pop ax
popf
clc
ret
;--- check shift state
kshft push ds
mov ax, BIOSEG ;data area segment
mov ds, ax
mov al, [BIOSHF] ;load first shift byte
pop ds
and al, SMASK ;mask bits
cmp al, SHIFT ;check if proper shift
jne kcdone ;exit if not
;--- execute resident function
call screen_func ;execute screen function
pop bx
pop ax
popf
stc
ret
ENDP
;========================================
; Interrupt 16H handler.
key2_han PROC NEAR
seg cs
mov func, ah ;save function number
cmp ah, 0 ;check if fetch key
je k2fet
cmp ah, 10H ;check if fetch extended key
je k2fet
cmp ah, 1 ;check if keyboard status
je k2stat
cmp ah, 11H ;check if extended keyboard status
je k2stat
seg cs
jmp int_16 ;branch to original keyboard handler
;--- fetch keystroke
k2fet1 seg cs
mov ah, func ;load function
k2fet pushf
seg cs
call int_16 ;call keyboard handler
call key_check ;check for hotkey
jc k2fet1 ;loop back if so
iret
;--- keyboard status
k2stat1 sub ah, ah ;fetch key function
pushf
seg cs
call int_16 ;call keyboard handler
seg cs
mov ah, func ;reload function
k2stat pushf
seg cs
call int_16 ;call keyboard handler
jz k2e2 ;exit if no key
call key_check ;check for hotkey
jc k2stat1 ;loop back if so
k2e2 retf 2 ;return with flags
ENDP
;========================================
; Interrupt 1CH handler.
tic_han PROC NEAR
seg cs
cmp timer, 0 ;check if timer zero
je tdone ;done if so
seg cs
dec timer ;decrement timer
jnz tdone
call video_off ;turn off screen
seg cs
and flags, NOT FORCE ;clear forced flag
tdone seg cs
jmp int_1C ;branch to old timer handler
ENDP
;========================================
; Interrupt 21H handler.
dos_han PROC NEAR
cmp ah, 2Bh ;check set date function
jne ddone
cmp cx, SIGN1 ;check if first signature matches
jne ddone
cmp dx, SIGN2 ;check if second signature matches
jne ddone
;--- external query
call screen_func ;execute screen function in BX
sub al, al ;clear error
mov dx, cs ;return segment
iret ;exit
;--- branch to old DOS
ddone seg cs
jmp int_21 ;branch to dos handler
ENDP
;========================================
; End of resident code/data.
end_res LABEL NEAR ;label marking end
;****************************************
; Transient Data
ENVIRO EQU 002CH ;offset of environtment in PSP
COMLINE EQU 0081H ;start of command line characters
;--- option table
OPT_HELP EQU 0 ;request help
OPT_INSTALL EQU 1 ;install
OPT_UNINSTALL EQU 2 ;uninstall
OPT_RESET EQU 3 ;reset timer
OPT_SHOW EQU 4 ;force visible
OPT_HIDE EQU 5 ;force hidden
OPT_TICKS EQU 6 ;set ticks
OPT_TIMEOUT EQU 7 ;force timeout
opttab LABEL WORD ;option routine table
DW OFFSET help
DW OFFSET install
DW OFFSET remove
DW OFFSET send_reset
DW OFFSET send_show
DW OFFSET send_hide
DW OFFSET send_ticks
DW OFFSET send_timeout
;--- messages
banner DB 13,10,'SLEEPER Mono Version '
DB VER_HI+'0', '.', (VER_LO/10)+'0', (VER_LO\10)+'0'
DB 'A Eric Tauck 8/2/1990',13,10,'$'
mes1a DB 'Sleeper installed with timer = ','$'
mes1b DB ' ticks',13,10,'$'
mes2 DB 'Error in options, run "SLEEPER ?" for help',13,10,'$'
mes3 DB 'Cannot uninstall Sleeper',13,10,'$'
mes4 DB 'Sleeper removed from memory',13,10,'$'
mes5 DB 'Sleeper must be installed first',13,10,'$'
mes6 DB 'Sleeper already installed',13,10,'$'
mes7a DB 'Sleeper reset with timer = ','$'
mes7b DB ' ticks',13,10,'$'
mes8 DB 'Sleeper timer reset',13,10,'$'
mes9 DB 'Screen forced visible',13,10,'$'
mes10 DB 'Screen forced hidden',13,10,'$'
mes11 DB 'Forced timeout',13,10,'$'
;--- help message
hmes LABEL BYTE
DB 13,10
DB 'Installation Options:',13,10
DB 13,10
DB ' SLEEPER install with a default timer value of 5 minutes',13,10
DB ' SLEEPER nnn install with a timer value of 1 to 3600 seconds',13,10
DB 13,10
DB 'Resident Options:',13,10
DB 13,10
DB ' SLEEPER v force visible screen (also when not resident)',13,10
DB ' SLEEPER h force hidden screen (also when not resident)',13,10
DB ' SLEEPER t force timeout',13,10
DB ' SLEEPER r reset timer',13,10
DB ' SLEEPER nnn reset timer with a value of 1 to 3600 seconds',13,10
DB ' SLEEPER u uninstall',13,10
DB 13,10
DB 'Keyboard Commands:',13,10
DB 13,10
DB ' ALT-CTL-V force visible screen',13,10
DB ' ALT-CTL-H force hidden screen',13,10
DB ' ALT-CTL-T force timeout',13,10
DB ' ALT-CTL-R reset timer ',13,10
DB '$'
;****************************************
; Transient Code
;========================================
; Macro to display a $ terminated string
display MACRO str
mov ah, 9 ;display function
mov dx, OFFSET str ;load address
int 21H ;execute
ENDM
;========================================
; Display the number in AX.
number PROC NEAR
mov bx, 10 ;base
sub cx, cx ;digit count
;--- determine decimal digits
numeval sub dx, dx ;zero for divide
div ax, bx ;divide by base
push dx ;save digit on stack
inc cx ;increment digit count
or ax, ax ;check if anything left
jnz numeval ;loop back if so
;--- display number
numdisp pop dx ;restore value
add dl, '0' ;convert to ASCII
mov ah, 2 ;display function
int 21H ;execute
loop numdisp ;loop for each digit
ret
ENDP
;========================================
; Call resident sleeper.
;
; In: BX= resident command.
;
; Out: DX= resident data segment; CY=
; set if error (not resident).
resident PROC NEAR
mov ah, 2Bh ;set date function
mov cx, SIGN1 ;signature one
mov dx, SIGN2 ;signature two
int 21H ;execute
sub al, 1 ;subtract (use SUB to set CY flag)
cmc ;set carry on error
ret
ENDP
;========================================
; Process command line.
;
; Out: BX= option number; CY= set if
; error.
options PROC NEAR
cld
;--- skip delimiters
mov si, COMLINE ;start of command line
mov bx, OPT_INSTALL
skdel lodsb ;load character
cmp al, 13 ;check if end of line
je optok ;exit if so
cmp al, ' ' ;check if delimiter
jbe skdel ;loop back if so
;--- check for standard options
mov dl, al ;save character
or al, 20H ;convert to lower-case
mov bx, OPT_RESET
cmp al, 'r'
je optok
mov bx, OPT_SHOW
cmp al, 'v'
je optok
mov bx, OPT_HIDE
cmp al, 'h'
je optok
mov bx, OPT_UNINSTALL
cmp al, 'u'
je optok
mov bx, OPT_HELP
cmp al, '?'
je optok
mov bx, OPT_TIMEOUT
cmp al, 't'
je optok
;--- convert number
mov bx, 10 ;base
sub cx, cx ;zero total
mov al, dl ;restore character
evall sub al, '0' ;convert to value
cmp al, 9 ;check if out of range
ja opterr ;jump if so
sub ah, ah
xchg ax, cx ;total in AX, digit value in CX
mul ax, bx ;total times base
add cx, ax ;new total
lodsb ;load next character
cmp al, ' ' ;check if delimiter
ja evall ;loop back if not
mov ax, 18 ;18/ticks per second
mul cx ;convert
or dx, dx ;check if too big
jnz opterr ;jump if so
push ax
mov ax, 5 ;plus .2/ticks per sec
xchg ax, cx
div ax, cx ;for every 5, add one more
pop dx
add dx, ax ;total ticks
jc opterr ;jump if too many
mov ticks, dx ;save ticks
mov bx, OPT_TICKS ;return function
;--- done
optok clc
ret
;--- error
opterr display mes2 ;show error message
stc
ret
ENDP
;========================================
; Display help screen.
;
; Out: AL= termination code.
help PROC NEAR
display hmes ;display help text
sub al, al ;no error
ret
ENDP
;========================================
; Install in memory.
;
; Out: AL= termination code (only if
; failure).
install PROC NEAR
;--- check if already installed
mov bx, NOTHING ;no resident operation
call resident ;link to resident version
jc noierr ;jump if okay
display mes6 ;display error message
mov al, -1 ;return error code
ret
;--- start installation
noierr call reset_timer ;reset timer
;--- display message
display mes1a ;first part
mov ax, ticks ;load timer value
call number ;display
display mes1b ;second part
;--- save keyboard interrupt 9
mov ax, 3509H ;get keyboard interrupt
int 21H ;execute
mov WORD int_09, bx ;save offset
mov WORD int_09+2, es ;save segment
;--- install keyboard interrupt 9
mov ax, 2509H ;set keyboard interrupt
mov dx, OFFSET key_han ;keyboard handler
int 21H ;execute
;--- save timer interrupt 1C
mov ax, 351CH ;get keyboard interrupt
int 21H ;execute
mov WORD int_1C, bx ;save offset
mov WORD int_1C+2, es ;save segment
;--- install timer interrupt 1C
mov ax, 251CH ;set interrupt 1C
mov dx, OFFSET tic_han ;timer tick handler
int 21H ;execute
call reset_timer ;reset timer
;--- save keyboard fetch interrupt 16
mov ax, 3516H ;get keyboard interrupt
int 21H ;execute
mov WORD int_16, bx ;save offset
mov WORD int_16+2, es ;save segment
;--- install keyboard fetch interrupt 16
mov ax, 2516H ;set interrupt 16
mov dx, OFFSET key2_han ;keyboard fetch handler
int 21H ;execute
;--- save DOS interrupt 21
mov ax, 3521H ;get keyboard interrupt
int 21H ;execute
mov WORD int_21, bx ;save offset
mov WORD int_21+2, es ;save segment
;--- install DOS interrupt 21
mov ax, 2521H ;set interrupt 21
mov dx, OFFSET dos_han ;DOS handler
int 21H ;execute
;--- install
mov dx, OFFSET end_res ;end of resident code
mov cl, 4
shr dx, cl ;convert to paragraph
inc dx ;round up, paragraphs to reserve
mov ax, 3100H ;resident-terminate with exit code 0
int 21H ;execute
ENDP
;========================================
; Remove from memory.
;
; Out: AL= termination code.
remove PROC NEAR
;--- check if installed
mov bx, NOTHING ;no resident operation
call resident ;link to resident version
jnc norerr ;jump if okay
display mes5 ;display error message
mov al, -1 ;return error code
ret
;--- start removal
norerr push ds
mov ds, dx ;switch to resident data segment
;=== verify vectors
mov cx, ds
;--- verify interrupt 9
mov ax, 3509H ;get interrupt
int 21H ;execute
cmp bx, OFFSET key_han ;check offset
jne verr
mov ax, es
cmp ax, cx ;check segment
jne verr
;--- verify interrupt 1C
mov ax, 351CH ;get interrupt
int 21H ;execute
cmp bx, OFFSET tic_han ;check offset
jne verr
mov ax, es
cmp ax, cx ;check segment
jne verr
;--- verify interrupt 16
mov ax, 3516H ;get interrupt
int 21H ;execute
cmp bx, OFFSET key2_han ;check offset
jne verr
mov ax, es
cmp ax, cx ;check segment
jne verr
;--- verify interrupt 21
mov ax, 3521H ;get interrupt
int 21H ;execute
cmp bx, OFFSET dos_han ;check offset
jne verr
mov ax, es
cmp ax, cx ;check segment
jne verr
jmps unhook
;--- error
verr pop ds
display mes3 ;display message
mov al, -1 ;error code
ret
;=== unhook interrupts
unhook push ds ;save resident segment
push ds
pop es ;transfer resident segment to ES
;--- unhook 9
mov ax, 2509H ;set interrupt function
seg es
mov dx, WORD int_09 ;offset
seg es
mov ds, WORD int_09+2 ;segment
int 21H ;execute
;--- unhook 16
mov ax, 2516H ;set interrupt function
seg es
mov dx, WORD int_16 ;offset
seg es
mov ds, WORD int_16+2 ;segment
int 21H ;execute
;--- unhook 1C
mov ax, 251CH ;set interrupt function
seg es
mov dx, WORD int_1C ;offset
seg es
mov ds, WORD int_1C+2 ;segment
int 21H ;execute
;--- unhook 21
mov ax, 2521H ;set interrupt function
seg es
mov dx, WORD int_21 ;offset
seg es
mov ds, WORD int_21+2 ;segment
int 21H ;execute
pop ds ;restore resident segment
;=== release memory
;--- release environment
mov ax, [ENVIRO] ;load environment segment
or ax, ax ;check if any
jz noenv
mov es, ax
mov ah, 49H ;release memory function
int 21H ;execute
;--- release code
noenv push ds
pop es
mov ah, 49H ;release memory function
int 21H ;execute
pop ds ;restore local DS
display mes4 ;display message
sub al, al ;no error
ret
ENDP
;========================================
; Reset resident sleeper.
send_reset PROC NEAR
mov bx, RESET ;command
call resident ;send to resident sleeper
jc sreserr
;--- success
display mes8 ;message
mov al, 0 ;no error
ret
;--- error
sreserr display mes5 ;error message
mov al, -1 ;error code
ret
ENDP
;========================================
; Force a timeout.
send_timeout PROC NEAR
mov bx, TIME ;command
call resident ;send to resident sleeper
jc stimerr
;--- success
display mes11 ;message
mov al, 0 ;no error
ret
;--- error
stimerr display mes5 ;error message
mov al, -1 ;error code
ret
ENDP
;========================================
; Show screen.
send_show PROC NEAR
mov bx, SHOW ;command
call resident ;send to resident sleeper
jnc sshook
;--- turn on screen
call video_on ;turn on video
;--- done
sshook display mes9 ;message
mov al, 0 ;no error
ret
ENDP
;========================================
; Hide screen.
send_hide PROC NEAR
mov bx, HIDE ;command
call resident ;send to resident sleeper
jnc shidok
;--- turn off screen
call video_off ;turn off video
;--- done
shidok display mes10 ;message
mov al, 0 ;no error
ret
ENDP
;========================================
; Set number of ticks in resident
; sleeper.
send_ticks PROC NEAR
;--- check if installed
mov bx, NOTHING ;no resident operation
call resident ;link to resident version
jc ticerr ;jump if not installed
;--- modify resident sleeper
mov ax, ticks ;load local tick count
push ds
mov ds, dx ;switch to resident segment
mov ticks, ax ;set new tick count
pop ds
mov bx, RESET ;command
call resident ;send to resident sleeper
;--- display message
display mes7a ;first part
mov ax, ticks ;load timer value
call number ;display
display mes7b ;second part
mov al, 0 ;no error
ret
;--- goto install
ticerr jmp install ;goto install
ENDP
;****************************************
; Program entry point.
start display banner ;display banner
call options ;parse command line
mov al, -1 ;error code if parameter error
jc term ;jump if error
shl bx ;adjust option number to offset
call WORD [opttab + bx] ;call option routine
;--- terminate, result code in AL
term mov ah, 4CH ;exit function
int 21H ;execute